/*
 * Copyright 2008-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.broadleafcommerce.core.web.controller.cart;

import org.broadleafcommerce.core.offer.domain.OfferCode;
import org.broadleafcommerce.core.offer.service.exception.OfferMaxUseExceededException;
import org.broadleafcommerce.core.order.domain.Order;
import org.broadleafcommerce.core.order.service.exception.AddToCartException;
import org.broadleafcommerce.core.order.service.exception.ItemNotFoundException;
import org.broadleafcommerce.core.order.service.exception.RemoveFromCartException;
import org.broadleafcommerce.core.order.service.exception.UpdateCartException;
import org.broadleafcommerce.core.pricing.service.exception.PricingException;
import org.broadleafcommerce.core.web.order.CartState;
import org.broadleafcommerce.core.web.order.model.AddToCartItem;
import org.broadleafcommerce.profile.web.core.CustomerState;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.ui.Model;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * In charge of performing the various modify cart operations
 * 
 * @author Andre Azzolini (apazzolini)
 */
public class BroadleafCartController extends AbstractCartController {
	
	protected static String cartView = "cart/cart";
	protected static String cartPageRedirect = "redirect:/cart";
	
	/**
	 * Renders the cart page.
	 * 
	 * If the method was invoked via an AJAX call, it will render the "ajax/cart" template.
	 * Otherwise, it will render the "cart" template.
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @throws PricingException
	 */
	public String cart(HttpServletRequest request, HttpServletResponse response, Model model) throws PricingException {
		return getCartView();
	}
	
	/**
	 * Takes in an item request, adds the item to the customer's current cart, and returns.
	 * 
	 * If the method was invoked via an AJAX call, it will render the "ajax/cart" template.
	 * Otherwise, it will perform a 302 redirect to "/cart"
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @param itemRequest
	 * @throws IOException
	 * @throws AddToCartException 
	 * @throws PricingException
	 */
	public String add(HttpServletRequest request, HttpServletResponse response, Model model,
			AddToCartItem itemRequest) throws IOException, AddToCartException, PricingException  {
		Order cart = CartState.getCart();
		
		// If the cart is currently empty, it will be the shared, "null" cart. We must detect this
		// and provision a fresh cart for the current customer upon the first cart add
		if (cart == null || cart.equals(orderService.getNullOrder())) {
			cart = orderService.createNewCartForCustomer(CustomerState.getCustomer(request));
		}
		
		cart = orderService.addItem(cart.getId(), itemRequest, false);
		cart = orderService.save(cart,  true);
		CartState.setCart(cart);
		
    	return isAjaxRequest(request) ? getCartView() : getCartPageRedirect();
	}
	
	/**
	 * Takes in an item request and updates the quantity of that item in the cart. If the quantity
	 * was passed in as 0, it will remove the item.
	 * 
	 * If the method was invoked via an AJAX call, it will render the "ajax/cart" template.
	 * Otherwise, it will perform a 302 redirect to "/cart"
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @param itemRequest
	 * @throws IOException
	 * @throws PricingException
	 * @throws UpdateCartException
	 * @throws RemoveFromCartException 
	 */
	public String updateQuantity(HttpServletRequest request, HttpServletResponse response, Model model,
			AddToCartItem itemRequest) throws IOException, UpdateCartException, PricingException, RemoveFromCartException {
		Order cart = CartState.getCart();
		
		cart = orderService.updateItemQuantity(cart.getId(), itemRequest, true);
		cart = orderService.save(cart, false);
		CartState.setCart(cart);
		
		if (isAjaxRequest(request)) {
			Map<String, Object> extraData = new HashMap<String, Object>();
			extraData.put("productId", itemRequest.getProductId());
			extraData.put("cartItemCount", cart.getItemCount());
			model.addAttribute("blcextradata", new ObjectMapper().writeValueAsString(extraData));
			return getCartView();
		} else {
			return getCartPageRedirect();
		}
	}
	
	/**
	 * Takes in an item request, updates the quantity of that item in the cart, and returns
	 * 
	 * If the method was invoked via an AJAX call, it will render the "ajax/cart" template.
	 * Otherwise, it will perform a 302 redirect to "/cart"
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @param nonAjaxSuccessUrl
	 * @param itemRequest
	 * @throws IOException
	 * @throws PricingException
	 * @throws RemoveFromCartException 
	 */
	public String remove(HttpServletRequest request, HttpServletResponse response, Model model,
			AddToCartItem itemRequest) throws IOException, PricingException, RemoveFromCartException {
		Order cart = CartState.getCart();
		
		cart = orderService.removeItem(cart.getId(), itemRequest.getOrderItemId(), false);
		cart = orderService.save(cart, true);
		CartState.setCart(cart);
		
		if (isAjaxRequest(request)) {
			Map<String, Object> extraData = new HashMap<String, Object>();
			extraData.put("cartItemCount", cart.getItemCount());
			extraData.put("productId", itemRequest.getProductId());
			model.addAttribute("blcextradata", new ObjectMapper().writeValueAsString(extraData));
			return getCartView();
		} else {
			return getCartPageRedirect();
		}
	}
	
	/**
	 * Cancels the current cart and redirects to the homepage
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @throws PricingException
	 */
	public String empty(HttpServletRequest request, HttpServletResponse response, Model model) throws PricingException {
		Order cart = CartState.getCart();
    	orderService.cancelOrder(cart);
		CartState.setCart(null);
    	return "redirect:/";
	}
	
	/** Attempts to add provided Offer to Cart
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @param customerOffer
	 * @return the return view
	 * @throws IOException
	 * @throws PricingException
	 * @throws ItemNotFoundException
	 * @throws OfferMaxUseExceededException 
	 */
	public String addPromo(HttpServletRequest request, HttpServletResponse response, Model model,
			String customerOffer) throws IOException, PricingException {
		Order cart = CartState.getCart();
		
		Boolean promoAdded = false;
		String exception = "";
		
		OfferCode offerCode = offerService.lookupOfferCodeByCode(customerOffer);
		
		if (offerCode!=null) {
			try {
				orderService.addOfferCode(cart, offerCode, false);
				promoAdded = true;
				cart = orderService.save(cart, true);
			} catch(OfferMaxUseExceededException e) {
				exception = "Use Limit Exceeded";
			}
		} else {
			exception = "Invalid Code";
		}
		
		CartState.setCart(cart);
		
		if (isAjaxRequest(request)) {
			Map<String, Object> extraData = new HashMap<String, Object>();
			extraData.put("promoAdded", promoAdded);
			extraData.put("exception" , exception);
			model.addAttribute("blcextradata", new ObjectMapper().writeValueAsString(extraData));
			return getCartView();
		} else {
		    model.addAttribute("exception", exception);
			return getCartView();
		}
		
	}
	
	/** Removes offer from cart
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @param offerId
	 * @return the return view
	 * @throws IOException
	 * @throws PricingException
	 * @throws ItemNotFoundException
	 * @throws OfferMaxUseExceededException 
	 */
	public String removePromo(HttpServletRequest request, HttpServletResponse response, Model model,
			Long offerCodeId) throws IOException, PricingException {
		Order cart = CartState.getCart();
		
		OfferCode offerCode = offerService.findOfferCodeById(offerCodeId);

		orderService.removeOfferCode(cart, offerCode, false);
		cart = orderService.save(cart, true);
		CartState.setCart(cart);

    	return isAjaxRequest(request) ? getCartView() : getCartPageRedirect();
	}

	public String getCartView() {
		return cartView;
	}

	public String getCartPageRedirect() {
		return cartPageRedirect;
	}
	
}
